\section{C\'odigo}

\subsection{C\'odigo fuente}

\subsubsection*{Polinomio}

\begin{code}

Object subclass: #Polinomio
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PLP-Tp3'
	
* otroPolinomio
	^ PolinomioMul new: self with: otroPolinomio.
	
+ otroPolinomio
	^ PolinomioSuma new: self with: otroPolinomio.

= otroPolinomio
	^ (self coeficientes) = (otroPolinomio coeficientes).
	
coeficientes
	"Se espera que las subclases devuelvan un diccionario con los coeficientes del polinomio"
	
	self subclassResponsibility
	
evaluar: unValor
	"Se espera que las subclases devuelvan la evaluacion del polinomio al sustituir X por unValor"
	
	self subclassResponsibility
	
grado
	"Se espera que las subclases devuelvan el grado del polinomio"
	
	self subclassResponsibility.

\end{code}

\subsubsection*{Constante}

\begin{code}
Polinomio subclass: #Constante
	instanceVariableNames: 'valor'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PLP-Tp3'
	
coeficientes
	"Devuelve un diccionario con los coeficientes"
	"Como se trata de una constante devolvemos el valor en el coeficiente 0"

     ^ Dictionary newFromPairs: { 0. valor.}.
    
evaluar: unValor
	"Retorna el valor de la constante"
	
	^valor.

grado
	"Devuelve el grado de una constante que es 0"
	
	^ 0.

initializeWith: unaConstante
	"Inicializa con una constante"

	valor := unaConstante. 

valor
	"Devuelve el valor de la constante"

	^ valor.
	
\end{code}


\subsubsection*{Variable}

\begin{code}
Polinomio subclass: #Variable
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PLP-Tp3'

coeficientes
	"Devuelve un diccionario con los coeficientes."
	"Como es una variable tiene el valor 1 en el coeficiente 1"

     ^ Dictionary newFromPairs: { 1. 1.}.
     
evaluar: unValor
	"Devuelve el valor pasado como parametro ya que es una variable"
	
	^unValor.

grado
	"Devuelve el grado del polinomio"

	^ 1.

\end{code}

\subsubsection*{PolinomioMul}

\begin{code}
Polinomio subclass: #PolinomioMul
	instanceVariableNames: 'polinomio1 polinomio2'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PLP-Tp3'

coeficientes
	"Devuelve un diccionario con los coeficientes"

	| diccionarioPolinomio1 diccionarioPolinomio2 valorPrevio diccionarioADevolver|
	diccionarioPolinomio1 := polinomio1 coeficientes. "Obtengo el diccionario de coeficientes de uno de los factores"
	diccionarioPolinomio2 := polinomio2 coeficientes. "Obtengo el diccionario de coeficientes del otro factor"
	
	diccionarioADevolver :=  Dictionary new. "Instancio un diccionario nuevo para devolver"
	
	"Itero por los dos diccionarios de los dos coeficientes"
	diccionarioPolinomio1 keys do: [ :each1 |
		diccionarioPolinomio2 keys do: [ :each2 |
				"Obtengo el valor intermedio del coeficiente para no pisarlo"
				valorPrevio := (diccionarioADevolver at:(each1 + each2)  ifAbsent:[0]) . 
				"Multiplico los coeficientes y se lo sumo al valor que estoy acumulando para ese coeficiente"
				diccionarioADevolver at: (each1 + each2) 
										put: valorPrevio + ( (diccionarioPolinomio1 at: each1) *  (diccionarioPolinomio2 at: each2)  )   ]   ].
	
	^ diccionarioADevolver.

evaluar: unValor
	"Evalua la multiplicacion de 2 polinomios reemplazando la X por unValor"
	
	|sonStrings resultado entiendePoli1 entiendePoli2 resPolinomio1 resPolinomio2|
	resPolinomio1 := polinomio1 evaluar:unValor. "Evaluo el primer polinomio factor"
	resPolinomio2 := polinomio2 evaluar:unValor. "Evaluo el otro polinomio factor"
	"Verifico si el resultado es un string para ver si algun objeto no entendio el mensaje de operacion"
	sonStrings := ((resPolinomio1 class name) = #String) & ((resPolinomio2 class name) = #String).
	
	"Si alguno de los polinomios no entendio una operacion se corta la operacion"
	(sonStrings and: [ (resPolinomio1 = 'AlguienNoEntiende') | (resPolinomio2 = 'AlguienNoEntiende' ) ]  )  
			ifTrue:[resultado := 'AlguienNoEntiende'.] 
			ifFalse:[				"En caso contrario verifico si los resultados parciales entienden la operacion *"			  
				entiendePoli1 := (polinomio1 evaluar:unValor) class canUnderstand: #*.
				entiendePoli2 := (polinomio2 evaluar:unValor) class canUnderstand: #*.
				(entiendePoli1 & entiendePoli2)
					ifTrue: [ resultado := resPolinomio1 * resPolinomio2 .  ]
					ifFalse: [ resultado := 'AlguienNoEntiende'. ].
			].
	^resultado.

grado
	"El grado de la multiplicacion de polinomios es la suma de los grados de los factores"
	"Suponemos que no se anula ningun coeficiente"
	
	^ (polinomio1 grado) + (polinomio2 grado).

multiplicarPolinomio: unPolinomio con: otroPolinomio
	"Multiplica un polinomio con el otro"

	polinomio1 := unPolinomio.
	polinomio2 := otroPolinomio.

\end{code}

\subsubsection*{PolinomioSuma}

\begin{code}

Polinomio subclass: #PolinomioSuma
	instanceVariableNames: 'polinomio1 polinomio2'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PLP-Tp3'

coeficientes
	"Devuelve un diccionario con los coeficientes"

	| diccionarioPolinomio1 diccionarioPolinomio2  diccionarioADevolver nuevoValor|
	diccionarioPolinomio1 := polinomio1 coeficientes. "Obtengo los coeficientes del primer polinomio"
	diccionarioPolinomio2 := polinomio2 coeficientes. "Obtengo los coeficientes del segundo polinomio"
	diccionarioADevolver := Dictionary new. "Creo un diccionario para devolver"
		
	diccionarioADevolver :=  diccionarioPolinomio1 deepCopy. "Realizo una copia de un diccionario"
	
	"Sumo los coeficientes de los dos diccionarios. "
	diccionarioPolinomio2 keys do: [ :each |
			nuevoValor := (diccionarioADevolver at:each ifAbsent:[0]) + (diccionarioPolinomio2 at: each) .
			diccionarioADevolver at:each put:nuevoValor.   
			].
			
	^ diccionarioADevolver.

evaluar: unValor
	"Evalua la suma de 2 polinomios reemplazando la X por unValor"
	
	|sonStrings resultado entiendePoli1 entiendePoli2 resPolinomio1 resPolinomio2|
	resPolinomio1 := polinomio1 evaluar:unValor. "Evaluo el primer polinomio sumando"
	resPolinomio2 := polinomio2 evaluar:unValor. "Evaluo el segundo sumando"
	"Verifico si el resultado es un string para ver si algun objeto no entendio el mensaje de operacion"
	sonStrings := ((resPolinomio1 class name) = #String) & ((resPolinomio2 class name) = #String).
	
	"Si alguno de los polinomios no entendio una operacion se corta la operacion"
	(sonStrings and: [ (resPolinomio1 = 'AlguienNoEntiende') | (resPolinomio2 = 'AlguienNoEntiende' ) ]  )     
			ifTrue:[resultado := 'AlguienNoEntiende'.] 
			"En caso contrario verifico si los resultados parciales entienden la operacion +"
			ifFalse:[							  
				entiendePoli1 := (polinomio1 evaluar:unValor) class canUnderstand: #+.
				entiendePoli2 := (polinomio2 evaluar:unValor) class canUnderstand: #+.
				(entiendePoli1 & entiendePoli2)
					ifTrue: [ resultado := resPolinomio1 + resPolinomio2.  ]
					ifFalse: [ resultado := 'AlguienNoEntiende'.  ].
			].
	^resultado.

grado
	"El grado de la suma de los polinomios es el grado mayor de los dos polinomios ya que los coeficientes no se anulan"
	
	(polinomio1 grado) > (polinomio2 grado) ifTrue: [ ^(polinomio1 grado) ]
		ifFalse: [ ^(polinomio2 grado) ].

sumarPolinomio: unPolinomio con: otroPolinomio
	"Suma un polinomio con otro"

	polinomio1 := unPolinomio.
	polinomio2 := otroPolinomio.
	
\end{code}

